package com.example.dayu521.sg_oss.service.impl;

import com.example.dayu521.sg_oss.controller.BaseOrder;
import com.example.dayu521.sg_oss.domain.Trade;
import com.example.dayu521.sg_oss.domain.TradeDetail;
import com.example.dayu521.sg_oss.domain.donain_mid.TradeParam;
import com.example.dayu521.sg_oss.service.PSettleService;
import com.example.dayu521.sg_oss.service.TradeDetailService;
import com.example.dayu521.sg_oss.service.TradeService;
import com.example.dayu521.sg_oss.service.feign.CartTCCService;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.example.dayu521.ORExecption;
import org.example.dayu521.OrRes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PSettleServiceImp implements PSettleService {
    @Autowired
    private CartTCCService cartTCCService;

    @Autowired
    private BaseOrder baseOrder;

    @Autowired
    private TradeService tradeService;

    @Autowired
    private TradeDetailService tradeDetailService;

    //对于分支事务,假定n个分支事务都来自于同一个参与服务.我们可以把这n个分支事务组成一个分支事务
    //这样,tcc的三个函数,原本每个函数需要调用n次,现在,只需要调用一次
    //唯一要注意的是回滚操作是复杂的

    @GlobalTransactional(rollbackFor= {ORExecption.class, Exception.class})
    @Override
    public void order_trade(TradeParam tp) throws ORExecption {
        log.info(STR."开始创建订单事务 XID -> \{RootContext.getXID()}");

        var trade = new Trade();
        var order_res = baseOrder.getnumber();
        if(!order_res.is_ok()){
            OrRes.error(59999,"获取订单号失败").throw_x();
        }

        //全局事务回滚时,设置state为2
        trade.setBusiness_id(order_res.res());
        trade.setUser_id(Long.parseLong(tp.getLogin_id()));
        trade.setSession_id(tp.getSettle_id());
        trade.setDate(LocalDateTime.now());
        trade.setType(0);
        trade.setState(0);
        trade.setBs_state(0);
        trade.setDescription("生成订单");

        if(!tradeService.save(trade)){
            OrRes.error(60001,"保存结算记录失败").throw_x();
        }

        //由全局事务回滚
        var x= cartTCCService.rob(Map.of("settle_id", UUID.randomUUID().toString(),"login_id",tp.getLogin_id()));
        if(!x.is_ok()|| x.res().isEmpty()){
            OrRes.error(50001,"购物车没有结算物品").throw_x();
        }

        //如果出错,不需要回滚,由trade表决定.这些数据不会被读取,可根据trade表决定删除
        var description=new StringBuilder("购买了: ");
        var tradeDetails = x.res().stream().map(i -> {
            var detail = new TradeDetail();
            detail.setTrade_bus_id(trade.getBusiness_id());
            detail.setDate(new Date());
            detail.setNum(i.num());
            detail.setPrice(i.price());
            detail.setP_id(i.id());
            detail.setP_name(i.title());
            detail.setSum_money(detail.getPrice().multiply(BigDecimal.valueOf(detail.getNum())));
            description.append(detail.getP_name()+"*"+detail.getNum());
            description.append(",");
            return detail;
        }).collect(Collectors.toList());

        tradeDetailService.saveBatch(tradeDetails);

        var sum_money=tradeDetails.stream().map(TradeDetail::getSum_money).reduce(BigDecimal.ZERO,BigDecimal::add);

        tradeService.lambdaUpdate().eq(Trade::getId,trade.getId())
                .set(Trade::getSum_money,sum_money)
                .set(Trade::getDescription,description.substring(0,description.length()>255?description.length():description.length()-1))
                .update();

        log.info("订单创建成功");
    }
}
